//@author A0081328H

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Storage {

	private static final String STRING_IS_NOT_DONE = "false";
	private static final String STRING_IS_DONE = "true";
	private static final String HEADER_DESCRIPTION = "description:";
	private static final String HEADER_DONE = "done:";
	private static final String HEADER_PROJECT = "project:";
	private static final String HEADER_PLACE = "place:";
	private static final String HEADER_ENDTIME = "endtime:";
	private static final String HEADER_STARTTIME = "starttime:";
	private static final String HEADER_TITLE = "title:";
	private static final String HEADER_ID = "id:";
	private static final String LOAD_DATE_UNABLE = "Unable to load date";
	private static final String LOAD_FILE_UNABLE = "Unable to load file";
	private static final String SAVE_DATA_UNABLE = "Unable to save data";
	private static final String NULL_ST_OR_ET = "NULL/NULL/NULL NULL:NULL";
	private static final String DATE_WO_TIME = "dd/MM/yyyy";
	private static final String DATE_W_TIME = "dd/MM/yyyy HH:mm";

	// Used by Logic
	public static ArrayList<Task> loadedData = new ArrayList<Task>();

	// public static ArrayList<String> textData = new ArrayList<String>();
	final static String FILE_NAME = "TaskBuddy.txt"; // specify file location
	private static final int STARTING_ID = 1;
	private static Logger logger = Logger.getLogger("Storage");

	public static void loadData() {
		if (isFileFound()) {
			BufferedReader reader = setupReader();
			if (reader != null) {
				readFileIntoArrayList(reader);
			}
		}
	}

	private static void readFileIntoArrayList(BufferedReader reader) {
		try {
			String currentLine = reader.readLine();
			Task newTask = new Task();
			while (currentLine != null) {

				if (isOfHeader(currentLine, HEADER_ID)) {
					newTask.id = getId(currentLine);
				}
				if (isOfHeader(currentLine, HEADER_TITLE)) {
					newTask.title = getStringWithoutHeader(currentLine,
							HEADER_TITLE);
				}
				if (isOfHeader(currentLine, HEADER_PLACE)) {
					newTask.place = getStringWithoutHeader(currentLine,
							HEADER_PLACE);
				}
				if (isOfHeader(currentLine, HEADER_PROJECT)) {
					newTask.project = getStringWithoutHeader(currentLine,
							HEADER_PROJECT);
				}
				if (isOfHeader(currentLine, HEADER_DESCRIPTION)) {
					if (newTask.description == Task.EMPTY_STRING) {
						newTask.description = getStringWithoutHeader(
								currentLine, HEADER_DESCRIPTION);
					} else {
						newTask.description += '\n'+getStringWithoutHeader(
								currentLine, HEADER_DESCRIPTION);
					}
				}

				if (isOfHeader(currentLine, HEADER_STARTTIME)) {
					newTask.startTime = getTime(currentLine, HEADER_STARTTIME);
				}

				if (isOfHeader(currentLine, HEADER_ENDTIME)) {
					newTask.endTime = getTime(currentLine, HEADER_ENDTIME);
				}
				if (isOfHeader(currentLine, HEADER_DONE)) {
					newTask.isDone = getIsDone(currentLine);
				}

				currentLine = reader.readLine();

				if (currentLine == null || currentLine.toLowerCase().startsWith(HEADER_ID)) {
					setEmptyStrings(newTask);
					if (isValidTask(newTask)) {
						loadedData.add(newTask);
					}
					newTask = new Task();
				}

			}
			reader.close();
		} catch (IOException e) {

		}

	}

	private static void setEmptyStrings(Task newTask) {
		if (isEmptyString(newTask.place)) {
			newTask.place = Task.EMPTY_STRING;
		}

		if (isEmptyString(newTask.description)) {
			newTask.description = Task.EMPTY_STRING;
		}

		if (isEmptyString(newTask.project)) {
			newTask.project = Task.EMPTY_STRING;
		}
		if (isEmptyString(newTask.title)) {
			newTask.title = Task.EMPTY_STRING;
		}

	}

	private static boolean getIsDone(String currentLine) {
		String isDoneString = getStringWithoutHeader(currentLine, HEADER_DONE);
		if (isDoneString.equalsIgnoreCase(STRING_IS_DONE)) {
			return true;
		}
		return false;
	}

	private static boolean isEmptyString(String stringToCheck) {
		if(stringToCheck == null){
			return true;
		}
		
		if (stringToCheck.trim().equals("")) {
			return true;
		}

		return false;
	}

	private static String getStringWithoutHeader(String currentLine,
			String header) {
		assert (isOfHeader(currentLine, header));
		return currentLine.replaceFirst(header, "");
	}

	private static Date getTime(String currentLine, String header) {
		String dateString = getStringWithoutHeader(currentLine, header);

		try {
			Date dateObject = new SimpleDateFormat(DATE_W_TIME)
					.parse(dateString);
			return dateObject;

		} catch (ParseException e) {
			try {
				Date dateObject = new SimpleDateFormat(DATE_WO_TIME)
						.parse(dateString);
				return dateObject;
			} catch (ParseException e1) {
				return Task.EMPTY_TIME;
			}

		}

	}

	private static int getId(String currentLine) {
		String idString = getStringWithoutHeader(currentLine, HEADER_ID);
		try {
			int taskId = Integer.parseInt(idString);
			return taskId;
		} catch (NumberFormatException e) {
			return Task.EMPTY_ID;
		}

	}

	private static boolean isOfHeader(String lineToCheck, String header) {
		return lineToCheck.toLowerCase().startsWith(header);

	}

	private static boolean isValidTask(Task newTask) {
		return isValidId(newTask.id) && isValidTitle(newTask.title)
				&& isValidDateRange(newTask.startTime, newTask.endTime);
	}

	private static boolean isValidDateRange(Date startTime, Date endTime) {
		if (startTime == Task.EMPTY_TIME || endTime == Task.EMPTY_TIME) {
			return true;
		} else if (startTime.after(endTime)) {

			return false;
		}
		return true;

	}

	private static BufferedReader setupReader() {
		try {
			return new BufferedReader(new FileReader(FILE_NAME));
		} catch (FileNotFoundException e) {
			logger.log(Level.INFO, "Fail to get BufferedReader");
			return null;
		}
	}

	private static boolean isFileFound() {
		File file = new File(FILE_NAME);
		return file.exists();
	}

	public static void saveData() {
		createNewFileIfNotThere();

		BufferedWriter writer = setupWriter();

		if (writer != null) {
			saveArrayListToFile(loadedData, writer);
		}
	}

	private static void saveArrayListToFile(ArrayList<Task> tasksToSave,
			BufferedWriter writer) {
		try {
			for (Task task : tasksToSave) {
				writeTaskInFile(task, writer);
			}
			writer.close();
		} catch (IOException e) {
			logger.log(Level.INFO, "Error when saving");
		}
	}

	private static void writeTaskInFile(Task task, BufferedWriter writer)
			throws IOException {
		assert (isValidId(task.id) && isValidTitle(task.title));

		writer.write(HEADER_ID + task.id);
		writer.newLine();
		writer.write(HEADER_TITLE + task.title);
		writer.newLine();
		if (task.startTime != Task.EMPTY_TIME) {
			writer.write(HEADER_STARTTIME
					+ new SimpleDateFormat(DATE_W_TIME).format(task.startTime));
			writer.newLine();
		}
		if (task.endTime != Task.EMPTY_TIME) {
			writer.write(HEADER_ENDTIME
					+ new SimpleDateFormat(DATE_W_TIME).format(task.endTime));
			writer.newLine();
		}
		if (task.place != Task.EMPTY_STRING) {
			writer.write(HEADER_PLACE + task.place);
			writer.newLine();
		}
		if (task.project != Task.EMPTY_STRING) {
			writer.write(HEADER_PROJECT + task.project);
			writer.newLine();
		}
		if (task.description != Task.EMPTY_STRING) {
			String lines[] = task.description.split("\\r?\\n");
			for (String line : lines) {
				writer.write(HEADER_DESCRIPTION + line);
				writer.newLine();
			}
		}

		if (task.isDone) {
			writer.write(HEADER_DONE + STRING_IS_DONE);
			writer.newLine();
		} else {
			writer.write(HEADER_DONE + STRING_IS_NOT_DONE);
			writer.newLine();
		}

	}

	private static boolean isValidTitle(String title) {
		if (title == Task.EMPTY_STRING) {
			return false;
		}
		if (title.trim().equals("")) {
			return false;
		}

		return true;
	}

	private static boolean isValidId(int id) {
		if (id < STARTING_ID) {
			return false;
		} else {
			return true;
		}
	}

	private static BufferedWriter setupWriter() {
		try {
			return new BufferedWriter(new FileWriter(FILE_NAME));
		} catch (IOException e) {
			logger.log(Level.INFO, "Fail to get BufferedWriter");
			return null;
		}
	}

	private static void createNewFileIfNotThere() {
		File file = new File(FILE_NAME);

		try {
			if (!file.exists()) {
				file.createNewFile();
			}
		} catch (IOException e) {
			logger.log(Level.INFO, "File creation failed");
		}

	}

}
